package com.king.hessian;

import java.lang.reflect.Method;
import java.util.*;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.CollectionUtils;

/**
 * 用于处理EmptyIfEmpty注解的MethodInterceptor
 */
public class EmptyIfEmptyMethodInterceptor implements MethodInterceptor {

    private final MethodInterceptor inner;

    public EmptyIfEmptyMethodInterceptor(MethodInterceptor inner) {
        this.inner = inner;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        EmptyIfEmpty emptyIfEmpty = method.getAnnotation(EmptyIfEmpty.class);
        if (emptyIfEmpty != null) {
            Object[] args = invocation.getArguments();
            int index = emptyIfEmpty.indexOfParam();
            if (index < 0 || index >= args.length) {
                throw new IllegalArgumentException("Bad @EmptyIfEmpty: paramIndex");
            }
            Object paramObject = args[index];
            if (isEmpty(paramObject)) {
                return createEmpty(method.getReturnType());
            }
            return inner.invoke(invocation);
        } else {
            return inner.invoke(invocation);
        }
    }

    private boolean isEmpty(Object paramObject) {
        if (paramObject == null) {
            return true;
        }
        if (paramObject instanceof Collection && CollectionUtils.isEmpty((Collection<?>)paramObject)) {
            return true;
        }
        if (paramObject instanceof Map && CollectionUtils.isEmpty((Map<?, ?>)paramObject)) {
            return true;
        }
        return false;
    }

    private Object createEmpty(Class<?> returnType) {
        if (returnType.isAssignableFrom(List.class)) {
            return Collections.emptyList();
        }
        if (returnType.isAssignableFrom(Set.class)) {
            return Collections.emptySet();
        }
        if (returnType.isAssignableFrom(Collection.class)) {
            return Collections.emptyList();
        }
        if (returnType.isAssignableFrom(Map.class)) {
            return Collections.emptyMap();
        }
        if (returnType.isAssignableFrom(HashMap.class)) {
            return new HashMap<>();
        }
        if (returnType.isAssignableFrom(TreeMap.class)) {
            return new TreeMap<>();
        }
        if (returnType.isAssignableFrom(HashSet.class)) {
            return new HashSet<>();
        }
        if (returnType.isAssignableFrom(TreeSet.class)) {
            return new TreeSet<>();
        }
        if (returnType.isAssignableFrom(ArrayList.class)) {
            return new ArrayList<>();
        }
        if (returnType.isAssignableFrom(LinkedList.class)) {
            return new LinkedList<>();
        }
        throw new IllegalArgumentException("Bad @EmptyIfEmpty: returnType");
    }

}
